查看原文
其他

黑客自述:我是如何侵入苹果、微软和数十家其他公司的...

21CTO 2022-05-25


黑客的工作在我们普通人看来,更像是一门看不懂的“玄学”。但这项玄学的背后,很多看起来高深莫测的网络攻击,使用的都是非常简单却有效的方法。


最近,一位名叫 Alex Birsan 的黑客,正式通过一种非常简单却实用的方法,发现了 30 多家科技公司存在的漏洞,并因此获得了高额的漏洞赏金。


下面是这位黑客在个人博客中的自述,我们可以通过这篇文章了解一下玄学背后的故事。




自从我开始学习如何编程以来,我一直对这一句简单的代码指令有些疑惑:


pip install package_name


某些编程语言(例如 Python)使用一种简单的官方方法来为项目安装依赖项。这些安装程序通常与公共代码存储库绑定,在那里任何人都可以自由上传代码包供他人使用。


当下载和使用其他来源的安装包时,我们基本上是信任其发行者在我们的机器上运行代码。那么这种盲目的信任会被恶意行为者利用吗?


答案是当然可以。


任何程序包托管服务都无法保证其用户上传的所有代码均不含恶意软件。过去的研究表明,「域名抢注(利用包名称的错字版本进行的攻击)」在获得对全球随机 PC 的访问方面非常有效。


其他众所周知的依赖项攻击路径包括使用各种方法来破坏现有软件包,或以不再存在的依赖项名称上传恶意代码。



▍想法



在 2020 年夏季尝试与我入侵 PayPal 时,Justin Gardner(@Rhynorater)分享了在 GitHub 上发现的有趣的 Node.js 源代码。


该代码是供内部 PayPal 使用的,并且在其 package.json 文件中似乎包含公共和私有依赖项的混合 —— 来自 npm 的公共软件包以及非公共软件包的名称,这些很可能是 PayPal 内部的私有软件包,由 PayPal 内部托管。因为这些名称当时在公共 npm 注册表中不存在。



这个逻辑会引起一些问题:


  • 如果以这些名称将恶意代码上传到 npm 会发生什么?PayPal 的一些内部项目是否有可能开始默认为新的公共软件包而不是私有软件包?
  • 开发人员或者一些自动化系统会开始在库中运行这些软件包吗?
  • 如果这种方法行得通,我们可以借助这个方式从科技企业获得漏洞赏金吗?
  • 这种攻击还会对其他公司起作用吗?

事不宜迟,我开始制定计划来回答这些问题。

这个想法是将我自己的“恶意” Node 程序包以所有无人认名的名称上载到npm注册表中,这将从安装它们的每台计算机上“打电话回家”。如果最终将任何软件包安装在 PayPal 拥有的服务器上,则其中的代码会立即通知我。

在这一步中,我觉得很重要的一点是,必须明确指出,在此研究过程中所针对的每个组织都已允许通过公共漏洞赏金计划或通过私人协议来对其安全性进行测试。未经授权,请勿尝试这种测试。




 ▍“总是 DNS”


值得庆幸的是,npm 允许在安装软件包时自动执行任意代码,这使我可以轻松创建一个 Node 软件包,该软件包收集有关通过其 preinstall 脚本安装在其上的每台计算机的一些基本信息。

为了在基于数据识别组织的能力与避免收集太多敏感信息之间取得平衡,我决定只记录用户名,主机名和每个唯一安装的当前路径。与外部 IP 一起使用的数据就足够了,可以帮助安全团队根据我的报告确定可能受到攻击的系统,同时避免将我的测试误认为是实际的攻击。

现在剩下的一件事 —— 如何将这些数据还给我?

知道大多数可能的目标都将位于受良好保护的公司网络内部,我认为 DNS 渗透是解决之道。



通过 DNS 协议将信息发送到我的服务器对于测试本身能否正常工作不是必不可少的,但它确实确保了在出站时不太可能阻止或检测到流量。

数据经过十六进制编码,并用作 DNS 查询的一部分,该 DNS 查询直接或通过中间解析器到达了我的自定义名称服务器。服务器配置为记录每个接收到的查询,实质上记录了下载软件包的每台计算机的记录。




 ▍多多益善


有了攻击的基本计划,现在是时候发现更多可能的目标了。

第一个策略是寻找类似的生态系统进行攻击。因此,我将代码移植到了 Python 和 Ruby 上,以便能够分别将相似的软件包上传到 PyPI(Python 软件包索引)和 RubyGems。

但是可以说,该测试最重要的部分是找到尽可能多的相关依赖项名称。

在搜索了一些目标公司的私有软件包名称的整整几天后,发现可以在 GitHub 以及主要软件包托管服务(偶然发布的内部软件包内部)甚至内部的主要软件包托管服务中找到许多其他名称,或者各种互联网论坛上的帖子。

但是,到目前为止,找到私有程序包名称的最佳位置竟然是在各家公司或平台的的 javascript 文件中。

显然,package.json 包含 javascript 项目依赖项名称的内部文件在其构建过程中会嵌入到公共脚本文件中,从而暴露内部包名称,这是很常见的。同样,require() 这些文件中泄漏的内部路径或调用也可能包含依赖项名称。苹果、Yelp 和特斯拉只是以这种方式公开内部名称的公司的一些例子。


在2020年下半年,由于@streaak的帮助和他出色的侦察技能,我们能够自动扫描属于目标公司的数百万个域,并提取数百个尚未在 npm 注册表中声明的 javascript 程序包名称。

然后,我将代码上传到所有找到的名称下的包托管服务中,并等待回调。




 ▍结果


成功率简直是惊人的。


从开发人员在自己的计算机上犯下的一次性错误,到内部或基于云的构建服务器配置不当,再到系统易受攻击的开发管道,一件事很明显:抢占有效的内部软件包名称几乎是一种不会失败的方法。一些最大的科技公司的网络,可以远程执行代码,并且可能允许攻击者在构建过程中添加后门。


迄今为止,我已经在超过 35 种组织中的所有三种经过测试的编程语言中检测到了这种类型的漏洞,我将这种漏洞称为「依赖混淆」。绝大多数受影响的公司属于 1000 多名员工类别,这很可能反映了大型组织内部使用内部软件库的普遍性。

由于更容易找到 javascript 依赖项名称,几乎所有已记录的回调中有 75% 来自 npm 软件包 —— 但这并不一定意味着 Python 和 Ruby 不太容易受到攻击。实际上,尽管在我的搜索过程中只能识别出属于八个组织的内部 Ruby 名称,但事实证明,其中有四家公司很容易通过 RubyGems 造成依赖混淆。


加拿大电子商务巨头 Shopify 是这样的公司之一,其构建系统 shopify-cloud 仅在我上传 Ruby 几个小时后自动安装了一个名为 Ruby 的 Ruby gem ,然后尝试在其中运行代码。Shopify 团队在一天之内准备好修复程序,并为发现问题的我提供了 30,000 美元的漏洞赏金。


在我于 2020 年 8 月上传到 npm 的 Node 包中的代码在其网络内的多台计算机上执行之后,苹果也提供了 30,000 美元的奖励。受影响的项目似乎与 Apple 的身份验证系统(外部称为 Apple ID)有关。


当我提出这个漏洞可能允许威胁者向 Apple ID 注入后门的想法时,Apple 并不认为这种影响水平可以准确地表示问题所在,而是说:

在运营服务中实现后门需要更复杂的事件序列,并且这是一个带有附加含义的非常特定的术语。
但是,Apple 确实确认使用此 npm 软件包技术可以在 Apple 服务器上执行远程代码。根据软件包安装的流程,该问题在我报告的两周内得到解决,但仅在发布此帖子之前不到一天就授予了赏金漏洞。


在针对其他公司的其他几次成功攻击中,可以看到在内部服务器和个人开发人员的 PC 上都安装了相同主题的 npm 软件包,其中一些安装通常是在软件包上载后数小时甚至数分钟进行的。


实际上,大多数已授予的 Bug 赏金都设置为每个程序的策略所允许的最高数额,有时甚至更高,这证实了依赖混淆 bug 的严重性通常很高。其他受影响的公司包括 Netflix,Yelp 和 Uber。




 ▍“这不是一个错误,这是一个功能”


尽管有大量的依赖混淆的发现,但一个细节在某种程度上仍然是(现在仍然是)尚不清楚:为什么会这样?此类漏洞的主要根源是什么?


可以理解,大多数受影响的组织都不愿透露有关其根本原因和缓解策略的更多技术细节,但是在我的研究过程中以及与安全团队的沟通中确实出现了一些有趣的细节。

例如,Python 依赖关系混乱的罪魁祸首似乎是错误地使用了“设计不安全”命令行参数 --extra-index-url。使用此参数 pip install library 指定您自己的包索引时,您可能会发现它可以按预期工作,但是 pip 幕后的实际操作是这样的:


  • 检查指定(内部)包索引上是否存在库
  • 检查公共包索引(PyPI)是否存在库
  • 安装找到的任何版本。如果两个软件包均存在,则默认从具有更高版本号的源进行安装。


因此,library 9000.0.0在上面的示例中,上传名为 PyPI 的程序包将导致依赖关系被劫持。


尽管这种行为已经广为人知,但仅在 GitHub 上搜索 --extra-index-url 就足以找到一些属于大型组织的易受攻击的脚本 —— 包括一个影响 Microsoft .NET Core 组件的错误。不幸的是,该漏洞可能允许向 .NET Core 添加后门程序,但该漏洞在 .NET Bug 赏金计划中未被发现。


Ruby 的 gem install --source 工作方式也与此类似,但是我无法确定其用法是否是我发现的根本原因。


当然,更改 --extra-index-url 为 --index-url 是一种快速而直接的解决方法,但是事实证明,依赖混淆的其他一些变体很难得到解决。


与此同时,Microsoft 还提供了类似的名为 Azure Artifacts 的程序包托管服务。根据我的一份报告,对该服务进行了一些小的改进,以确保它可以为依赖项混淆漏洞提供可靠的解决方法。有趣的是,没有通过测试 Azure Artifacts 本身发现此问题,而是通过成功攻击 Microsoft 自己的基于云的 Office 365 来发现此问题,该报告得到了 Azure 可能获得的最高奖励 40,000 美元。




▍未来的研究?


尽管许多大型科技公司已经意识到这种漏洞,并已在其基础架构中对其进行了修复,或者正在努力实施缓解措施,但我仍然感到还有很多发现的感觉。


具体来说,我相信找到泄漏内部程序包名称的新方法将揭示更多易受攻击的系统,而寻找替代的编程语言和目标存储库将揭示依赖混淆错误的其他攻击面。


话虽这么说,无论您的经验水平如何,我都竭诚鼓励您花一些时间在脑海中尝试一下该想法 —— 无论它是否与依赖项管理安全性相关。

作者:Alex Birsan   转自|SegmentFault

原文链接:

https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610


相关阅读:


OAuth2 与 JWT:如何设计安全的API

HTTPS 为何是如此安全?

天才黑客,阿里安全科学家吴翰清:做对事只能赢一场,跟对人可以赢一生


关于21CTO

21CTO.com是中国互联网第一技术社交与学习平台。为CTO、技术总监,技术专家,架构师、技术经理,高级研发工程师、PM等提供学习成长,教育培训,工作机会、人脉影响力等产品,同时为企业提供人才招聘,企业培训,软件研发等服务。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存